﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Diagnostics;
using Microsoft.SqlServer.Management.Smo;
using System.IO;
using System.Xml.Linq;
using System.Linq;


namespace SQLDocumentationX
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            picProgress.Visible = false;
        }

        private void btLink_Click(object sender, EventArgs e)
        {
            try
            {
                Process.Start("mailto://ares@xizhang.com");
            }
            catch 
            {
                MessageBox.Show(
                    string.Format("有关该工具的反馈，请通过{0}联系作者.", "ares@xizhang.com"), "技术支持", MessageBoxButtons.OK, MessageBoxIcon.Information);

            }
        }

        private void btStart_Click(object sender, EventArgs e)
        {
            if (CheckInput())
            { 
                //读取所有对象，生成XML文件
                //创建一个子目录



                string outputdir = Path.Combine(
                    Application.StartupPath,
                    txtDatabase.Text + "_" + DateTime.Now.ToString("yyyyMMddHHmmss"));
                Directory.CreateDirectory(outputdir);


                Environment.CurrentDirectory = outputdir;//设置到指定目录为工作目录

                //将资源文件复制到输出目录中
                CopyResourceFile(outputdir);


                BackgroundWorker worker = new BackgroundWorker();
                worker.DoWork += new DoWorkEventHandler(worker_DoWork);
                worker.WorkerReportsProgress = true;
                worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
                worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
                worker.RunWorkerAsync(outputdir);

                btStart.Enabled = false;
                picProgress.Visible = true;

            }
        }

        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            lbCurrentStatus.Text = "正在处理:"+e.UserState.ToString();
        }

        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            btStart.Enabled = true;
            picProgress.Visible = false;
            lbCurrentStatus.Text = "就绪";

            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
            else
            {
                if (MessageBox.Show("工作已经完成，是否要立即打开该数据库文档?", "操作完成", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    Process.Start("Index.htm");
                }
            }
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            string outputdir = e.Argument.ToString();
            BackgroundWorker worker = (BackgroundWorker)sender;
            //准备生成文档
            DatabaseHelper helper = new DatabaseHelper();

            ///生成数据库树状信息，以及作为chm文档的目录文件的内容
            StringBuilder treeBuilder = new StringBuilder();
            treeBuilder.AppendFormat("d.add(0,-1,'{0}','DatabaseSummary.xml');", db.Name);//根节点
            treeBuilder.Append("d.add(1,0,'表(Tables)','tables.xml');");
            int seq = 5;

            //生成数据库主文档
            worker.ReportProgress(0, "数据库主文档");
            XDocument dbSummary = helper.GetDatabaseSummary(db);
            dbSummary.Save(Path.Combine(outputdir, "DatabaseSummary.xml"));


            //依次生成所有的表和视图，函数，存储过程
            worker.ReportProgress(0, "表格");
            XDocument tables = helper.GetObjectCollection("Tables", dbSummary);
            foreach (var tb in tables.Root.Elements("Item"))
            {
                
                string schema = tb.Element("Schema").Value;
                string name = tb.Element("Name").Value;
                worker.ReportProgress(0, string.Format("表:{0}.{1}",schema,name));

                Table table = db.Tables[name, schema];
                XDocument tabledoc = helper.GetTableView(table, svr, version, "Table");
                tabledoc.Save(Path.Combine(outputdir, string.Format("{0}.{1}.xml", schema, name)));

                treeBuilder.AppendFormat("d.add({0},1,'{1}','{1}.xml');",seq++,string.Format("{0}.{1}",schema,name));
            }
            tables.Save(Path.Combine(outputdir, "Tables.xml"));

            worker.ReportProgress(0, "视图");
            treeBuilder.Append("d.add(2,0,'视图(Views)','Views.xml');");
            XDocument views = helper.GetObjectCollection("Views", dbSummary);
            foreach (var vw in views.Root.Elements("Item"))
            {
                string schema = vw.Element("Schema").Value;
                string name = vw.Element("Name").Value;
                worker.ReportProgress(0, string.Format("视图:{0}.{1}", schema, name));

                Microsoft.SqlServer.Management.Smo.View view = db.Views[name, schema];
                XDocument viewdoc = helper.GetTableView(view, svr, version, "View");
                viewdoc.Save(Path.Combine(outputdir, string.Format("{0}.{1}.xml", schema, name)));

                treeBuilder.AppendFormat("d.add({0},2,'{1}','{1}.xml');", seq++, string.Format("{0}.{1}", schema, name));
            }
            views.Save(Path.Combine(outputdir, "Views.xml"));

            worker.ReportProgress(0, "函数");
            treeBuilder.Append("d.add(3,0,'函数(Functions)','Functions.xml');");
            XDocument functions = helper.GetObjectCollection("Functions", dbSummary);
            foreach (var item in functions.Root.Elements("Item"))
            {
                string schema = item.Element("Schema").Value;
                string name = item.Element("Name").Value;
                worker.ReportProgress(0, string.Format("函数:{0}.{1}", schema, name));

                UserDefinedFunction func = db.UserDefinedFunctions[name, schema];
                XDocument funcdoc = helper.GetProcedure(func, svr, version, "Function");
                funcdoc.Save(Path.Combine(outputdir, string.Format("{0}.{1}.xml", schema, name)));

                treeBuilder.AppendFormat("d.add({0},3,'{1}','{1}.xml');", seq++, string.Format("{0}.{1}", schema, name));
            }
            functions.Save(Path.Combine(outputdir, "Functions.xml"));

            worker.ReportProgress(0, "存储过程");
            treeBuilder.Append("d.add(4,0,'存储过程(StoredProcedure)','StoredProcedures.xml');");
            XDocument storedProcedures = helper.GetObjectCollection("StoredProcedures", dbSummary);
            foreach (var item in storedProcedures.Root.Elements("Item"))
            {
                string schema = item.Element("Schema").Value;
                string name = item.Element("Name").Value;
                worker.ReportProgress(0, string.Format("存储过程:{0}.{1}", schema, name));

                StoredProcedure proc = db.StoredProcedures[name, schema];
                XDocument procdoc = helper.GetProcedure(proc, svr, version, "StoredProcedure");
                procdoc.Save(Path.Combine(outputdir, string.Format("{0}.{1}.xml", schema, name)));

                treeBuilder.AppendFormat("d.add({0},4,'{1}','{1}.xml');", seq++, string.Format("{0}.{1}", schema, name));
            }

            storedProcedures.Save(Path.Combine(outputdir, "StoredProcedures.xml"));

            //生成左边的那个DatabaseTree.htm文件

            File.WriteAllText("DatabaseTree.htm", File.ReadAllText(Path.Combine(Application.StartupPath, "DatabaseTree.htm"),Encoding.UTF8).Replace("$contents$", treeBuilder.ToString()), Encoding.UTF8);


        }




        private void CopyResourceFile(string outputdir)
        {

            CopyFolder(outputdir, "Style");
            CopyFolder(outputdir, "Img");
            CopyFolder(outputdir, "Tree");
            File.Copy(Path.Combine(Application.StartupPath, "Index.htm"), Path.Combine(outputdir, "Index.htm"));
            File.Copy(Path.Combine(Application.StartupPath, "Default.css"), Path.Combine(outputdir, "Default.css"));
        }


        private void CopyFolder(string outputdir, string folder)
        {
            string sourcedirpath = Path.Combine(Application.StartupPath, folder);
            string destdirpath = Path.Combine(outputdir, folder);
            if (!Directory.Exists(destdirpath))
                Directory.CreateDirectory(destdirpath);

            DirectoryInfo sourcedir = new DirectoryInfo(sourcedirpath);

            foreach (var file in sourcedir.GetFiles())
            {
                file.CopyTo(Path.Combine(destdirpath, file.Name));
            }
        }


        Server svr = null;
        Database db = null;
        string version = default(string);

        bool CheckInput() {
            bool result = false;
            try
            {
                svr = new Server(txtServer.Text);
                db = svr.Databases[txtDatabase.Text];
                version = cboVersion.Text;
                //这里注册几个默认的属性，因为后面检索的时候会用到
                svr.SetDefaultInitFields(
                    typeof(Table), 
                    new string[] { "IsSystemObject" });
                svr.SetDefaultInitFields(
                    typeof(Microsoft.SqlServer.Management.Smo.View), 
                    new string[] { "IsSystemObject", "IsEncrypted" });
                svr.SetDefaultInitFields(
                    typeof(StoredProcedure), 
                    new string[] { "IsSystemObject", "IsEncrypted" });
                svr.SetDefaultInitFields(
                    typeof(UserDefinedFunction), 
                    new string[] { "IsSystemObject", "IsEncrypted" });

                result = true;
            }
            catch(Exception ex)
            {
                MessageBox.Show(
                    "在连接服务器时发生如下错误:" + ex.Message,
                    "连接失败",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Warning);
            }
            return result;

        }
    }
}
